<script setup>
import {
  ElDatePicker,
  ElFormItem,
  ElIcon,
  ElInput,
  ElInputNumber,
  ElMessage,
  ElOption,
  ElPopover,
  ElSelect,
} from 'element-plus'
import { getProjectProgressInfo } from '@/assets/api/project-progress'
import { Check, Close } from '@element-plus/icons-vue'
import {
  addTaskInfo,
  addTcTaskItem,
  deleteTcTask,
  deleteTcTaskItem,
  editTcTaskItem,
  updateTask,
} from '@/assets/api/task'
import dayjs from 'dayjs'
import { useDictionary } from '@/use/use-dictionary'
import { getProjectMember } from '@/assets/api/project'

const props = defineProps({
  projectId: {
    type: [String, Number],
    required: true,
  },
})

const dict = useDictionary(['task_status'])

const oldPopoverRef = ref()

const hasAdd = ref(false)

const requiredValidator = (value, callback) => {
  return value ? callback() : callback(new Error())
}

const columns = reactive([
  {
    label: '名称',
    key: 'name',
    width: 150,
    render: (h, { node, data, level }) => {
      const popoverRef = ref()
      return data.isAdd || data.isEdit
        ? createFormItem(
            data,
            {
              prop: 'name',
              rules: {
                validator: (rule, value, callback) => requiredValidator(data.name, callback),
                trigger: 'blur',
              },
            },
            h(ElInput, {
              modelValue: data.name,
              'onUpdate:modelValue': (v) => {
                data.name = v.trim()
              },
            })
          )
        : h(
            ElPopover,
            {
              ref: popoverRef,
              trigger: 'contextmenu',
              placement: 'right',
              popperClass: 'more-operation-popover',
              width: 'auto',
              hideAfter: 0,
              onShow: () => {
                if (oldPopoverRef.value !== popoverRef.value) {
                  oldPopoverRef.value?.hide()
                  oldPopoverRef.value = popoverRef.value
                }
              },
              onHide: () => {
                data.isAdd = false
              },
            },
            {
              default: () => createContentMenuBtns(h, node, data, level),
              reference: () =>
                h(
                  'div',
                  {
                    class: 'text-overflow-ellipsis',
                  },
                  data.name
                ),
            }
          )
    },
  },
  {
    label: '开始时间',
    key: 'startTime',
    width: 95,
    render: (h, { data }) => {
      return data.isAdd || data.isEdit
        ? createFormItem(
            data,
            {
              prop: 'startTime',
              rules: {
                validator: (rule, value, callback) => requiredValidator(data.startTime, callback),
                trigger: 'blur',
              },
            },
            h(ElDatePicker, {
              type: 'datetime',
              modelValue: data.startTime,
              clearable: false,
              'onUpdate:modelValue': (v) => {
                data.startTime = dayjs(v).valueOf()
                v && planDateChange(data, [v, data.endTime])
              },
              disabledDate: (date) => {
                return (
                  dayjs(data.endTime || '').isBefore(date, 'day') ||
                  dayjs(
                    data.parentNode.planBegin || data.parentNode.planBegintime || data.parentNode.itemBegin
                  ).isAfter(date, 'day') ||
                  dayjs(data.parentNode.planEnd || data.parentNode.planEndtime || data.parentNode.itemEnd).isBefore(
                    date,
                    'day'
                  )
                )
              },
            })
          )
        : h('span', data.startTime)
    },
  },
  {
    label: '结束时间',
    key: 'endTime',
    width: 95,
    render: (h, { data }) => {
      return data.isAdd || data.isEdit
        ? createFormItem(
            data,
            {
              prop: 'endTime',
              rules: {
                validator: (rule, value, callback) => requiredValidator(data.endTime, callback),
                trigger: 'blur',
              },
            },
            h(ElDatePicker, {
              type: 'datetime',
              clearable: false,
              modelValue: data.endTime,
              'onUpdate:modelValue': (v) => {
                data.endTime = dayjs(v).valueOf()
                v && planDateChange(data, [data.startTime, v])
              },
              disabledDate: (date) => {
                return (
                  dayjs(data.startTime || '').isAfter(date, 'day') ||
                  dayjs(
                    data.parentNode.planBegin || data.parentNode.planBegintime || data.parentNode.itemBegin
                  ).isAfter(date, 'day') ||
                  dayjs(data.parentNode.planEnd || data.parentNode.planEndtime || data.parentNode.itemEnd).isBefore(
                    date,
                    'day'
                  )
                )
              },
            })
          )
        : h('span', data.endTime)
    },
  },
  {
    label: '计划人天',
    key: 'planCostDay',
    width: 90,
    render: (h, { data }) => {
      return (data.isAdd || data.isEdit) && data.isTask
        ? createFormItem(
            data,
            {
              prop: 'planCostDay',
              rules: {
                validator: (rule, value, callback) => requiredValidator(data.planCostDay, callback),
                trigger: 'blur',
              },
            },
            h(ElInputNumber, {
              modelValue: data.planCostDay,
              controls: false,
              'onUpdate:modelValue': (v) => {
                data.planCostDay = v
              },
            })
          )
        : h('span', data.planCostDay)
    },
  },
  {
    label: '任务责任人',
    width: 90,
    render: (h, { data }) => {
      return data.isAdd || data.isEdit
        ? createFormItem(
            data,
            {
              prop: 'userId',
              // rules: {
              //   validator: (rule, value, callback) => requiredValidator(data.userId, callback),
              //   trigger: 'change',
              // },
            },
            h(
              ElSelect,
              {
                modelValue: data.userId === -1 ? '' : data.userId,
                clearable: true,
                'onUpdate:modelValue': (v) => {
                  if (v) {
                    data.userId = v
                  } else {
                    data.userId = -1
                  }
                },
              },
              () => createOptions(h, projectMemberList.value)
            )
          )
        : h('span', data.userName)
    },
  },
  {
    label: '',
    show: hasAdd,
    width: 50,
    render: (h, { data }) => {
      return data.isAdd || data.isEdit
        ? [
            h(
              ElIcon,
              {
                onClick: () => {
                  submit(data)
                },
              },
              () => h(Check)
            ),
            h(
              ElIcon,
              {
                onClick: () => {
                  if (data.projectId) {
                    getProjectProgressInfoData()
                  } else {
                    const index = data.parentNode.childrenList.findIndex((i) => i === data)
                    data.parentNode.childrenList.splice(index, 1)
                  }
                },
              },
              () => h(Close)
            ),
          ]
        : null
    },
  },
])

const projectInfo = ref({})

const tasks = ref([])

const projectMemberList = ref([])

const searchForm = reactive({
  taskTitle: '',
  taskUserId: null,
  currentStatus: null,
})

watchEffect(() => {
  hasAdd.value = findHasAdd(tasks.value)
})

getProjectProgressInfoData()

function getProjectProgressInfoData() {
  const params = {
    tcTaskItems: {
      projectId: props.projectId,
    },
    tcTaskInfo: {
      ...searchForm,
      projectId: props.projectId,
    },
  }
  getProjectProgressInfo(params).then((res) => {
    if (res.code === 200) {
      projectInfo.value = res.data
      tasks.value = buildItemData(res.data.tcTaskItemsList, projectInfo.value)
      projectInfo.value.childrenList = tasks.value
      // projectMemberList.value = projectInfo.value.tcProjectMembers
    } else {
      ElMessage.error(res.msg)
    }
  })
}

getProjectMemberData()
function getProjectMemberData() {
  //查询项目成员
  getProjectMember({ projectId: props.projectId, effectFlag: 1 }).then((res) => {
    if (res.code === 200) {
      projectMemberList.value = res.rows
    } else {
      ElMessage.error(res.msg)
    }
  })
}

function buildItemData(list, parentNode) {
  return list.map((i) => {
    i.id = i.itemId
    i.name = i.itemName
    i.startTime = dayjs(i.itemBegin).format('YYYY-MM-DD')
    i.endTime = dayjs(i.itemEnd).format('YYYY-MM-DD')
    // i.startTime = i.itemBegin
    // i.endTime = i.itemEnd
    i.userId = i.itemManager
    i.userName = i.itemManagerName
    i.parentNode = parentNode
    i.isEdit = false
    i.isAdd = false
    i.isTask = false
    i.childrenList = i.itemsChildren.length ? buildItemData(i.itemsChildren, i) : buildTaskData(i.children, i)
    return i
  })
}

function buildTaskData(list, parentNode) {
  return (list || []).map((i) => {
    i.id = i.taskId
    i.name = i.taskTitle
    i.startTime = i.planBegintime
    i.endTime = i.planEndtime
    i.userId = i.taskUserId
    i.userName = i.taskUserName
    i.parentNode = parentNode
    i.isEdit = false
    i.isAdd = false
    i.isTask = true
    i.childrenList = buildTaskData(i.children, i)
    return i
  })
}

function findHasAdd(list) {
  return list.some((i) => {
    if (i.isAdd || i.isEdit) {
      return true
    }
    if (i.childrenList.length) {
      return findHasAdd(i.childrenList)
    }
    return false
  })
}

const addTaskVisible = ref(false)
const parentData = ref({})
const taskForm = ref({})

async function submit(data) {
  Promise.all(Object.values(data.forms).map((i) => toValue(i).validate()))
    .then(async () => {
      const res = await (data.isTask ? submitTask : submitGroup)(data)
      if (res.code === 200) {
        ElMessage.success('提交成功')
        getProjectProgressInfoData()
      } else {
        ElMessage.error(res.msg)
      }
    })
    .catch((err) => {
      console.warn(err)
    })
}

// 提交阶段
function submitGroup(data) {
  return new Promise(async (resolve) => {
    const params = {
      itemId: data.itemId,
      parentId: data.parentId,
      projectId: props.projectId,
      itemName: data.name,
      itemManager: data.userId,
      itemBegin: data.startTime,
      itemEnd: data.endTime,
    }
    const isAdd = !params.itemId
    const res = await (isAdd ? addTcTaskItem : editTcTaskItem)(params)
    resolve(res)
  })
}

// 提交任务
function submitTask(data) {
  return new Promise(async (resolve) => {
    const params = {
      taskId: data.taskId,
      itemId: data.itemId,
      parentTaskId: data.parentTaskId,
      taskTitle: data.name,
      projectId: props.projectId,
      taskProp: props.taskProp ? props.taskProp : 1,
      planBegintime: data.startTime,
      planEndtime: data.endTime,
      taskUserId: data.userId,
    }
    const isAdd = !params.taskId
    const res = await (isAdd ? addTaskInfo : updateTask)(params)
    resolve(res)
  })
}

async function remove(data) {
  try {
    const res = await (data.isTask ? removeTask : removeGroup)(data)
    if (res.code === 200) {
      ElMessage.success('删除成功')
      getProjectProgressInfoData()
    } else {
      ElMessage.error(res.msg)
    }
  } catch (err) {
    ElMessage.warning(err)
  }
}

function removeGroup(data) {
  return new Promise(async (resolve, reject) => {
    if (data.children && data.children.length) {
      reject('此阶段已有任务, 无法删除')
      return
    }
    const res = await deleteTcTaskItem(data.itemId)
    resolve(res)
  })
}

function removeTask(data) {
  return new Promise(async (resolve, reject) => {
    if (data.children && data.children.length) {
      reject('此任务已有子任务, 无法删除')
      return
    }
    const res = await deleteTcTask(data.taskId)
    resolve(res)
  })
}

function handleAddTaskClose() {
  taskForm.value = {}
}

function planDateChange(data, date) {
  const diff = dayjs(date[1]).diff(dayjs(date[0]), 'day', true)
  const decimal = diff % 1
  data.planCostDay = Math.trunc(diff) + (decimal && (decimal > 0.5 ? 1 : 0.5))
  data.planCostHour = data.planCostDay * 8
}

function createFormItem(data, props, slot) {
  const itemRef = ref()
  if (!data.forms) {
    data.forms = {}
  }
  data.forms[props.prop] = itemRef
  return h(ElFormItem, { ...props, ref: itemRef, showMessage: false }, () => slot)
}

function createOptions(h, list) {
  return list.map((i) => {
    return h(ElOption, { label: i.userName, value: i.userId })
  })
}

function createContentMenuBtns(h, node, data, level) {
  return [
    // 第一级才能添加阶段和子阶段
    level === 1 &&
      h(
        'div',
        {
          class: 'btn',
          onClick: () => {
            const index = data.parentNode.childrenList.findIndex((i) => i === data)
            data.parentNode.childrenList.splice(index + 1, 0, {
              id: new Date().getTime(),
              isAdd: true,
              isEdit: false,
              isTask: false,
              startTime: dayjs().startOf('day').valueOf(),
              endTime: dayjs().endOf('day').valueOf(),
              parentNode: data.parentNode,
              childrenList: [],
            })
            oldPopoverRef.value.hide()
          },
        },
        '添加阶段'
      ),
    level === 1 &&
      data.children.length === 0 &&
      h(
        'div',
        {
          class: 'btn',
          onClick: () => {
            node.extend(true)
            data.childrenList.splice(0, 0, {
              id: new Date().getTime(),
              isAdd: true,
              isEdit: false,
              isTask: false,
              startTime: dayjs().startOf('day').valueOf(),
              endTime: dayjs().endOf('day').valueOf(),
              parentId: data.itemId,
              parentNode: data,
              childrenList: [],
            })
            oldPopoverRef.value.hide()
          },
        },
        '添加子阶段'
      ),
    // 在没有子阶段情况下才能添加任务
    ((level === 1 && data.itemsChildren.length === 0) || level === 2 || (level === 3 && data.parentTaskId === 0)) &&
      h(
        'div',
        {
          class: 'btn',
          onClick: () => {
            node.extend(true)
            data.childrenList.splice(0, 0, {
              id: new Date().getTime(),
              isAdd: true,
              isEdit: false,
              isTask: true,
              startTime: dayjs().startOf('day').valueOf(),
              endTime: dayjs().endOf('day').valueOf(),
              planCostDay: 1,
              checkFlag: 1,
              taskProp: 1,
              itemId: data.itemId,
              parentTaskId: data.taskId,
              parentNode: data,
              childrenList: [],
            })
            oldPopoverRef.value.hide()
          },
        },
        '快捷添加任务'
      ),
    ((level === 1 && data.itemsChildren.length === 0) || level === 2 || (level === 3 && data.parentTaskId === 0)) &&
      h(
        'div',
        {
          class: 'btn',
          onClick: () => {
            taskForm.value = {
              parentTaskId: data.taskId,
              itemId: data.itemId,
              startTime: dayjs().startOf('day').valueOf(),
              endTime: dayjs().endOf('day').valueOf(),
              planCostDay: 1,
              checkFlag: 1,
            }
            parentData.value = data
            addTaskVisible.value = true
            oldPopoverRef.value.hide()
          },
        },
        '添加任务'
      ),
    h(
      'div',
      {
        class: 'btn',
        onClick: () => {
          data.isEdit = true
        },
      },
      '编辑'
    ),
    h(
      'div',
      {
        class: 'btn',
        onClick: () => {
          remove(data)
        },
      },
      '删除'
    ),
  ]
}

const tabVal = ref(1)
function tabChangRadio(val) {
  console.log('val', typeof val)
}
</script>

<template>
  <div class="project-progress">
    <div class="project-info">
      <el-descriptions :title="projectInfo.projectName" :column="4">
        <el-descriptions-item label="项目周期">
          {{ dayjs(projectInfo.planBegin).format('YYYY-MM-DD') }} 至
          {{ dayjs(projectInfo.planEnd).format('YYYY-MM-DD') }}
        </el-descriptions-item>
        <el-descriptions-item label="历经自然日">{{ projectInfo.naturalDay }}天</el-descriptions-item>
        <el-descriptions-item label="历经工作日">{{ projectInfo.workDay }}天</el-descriptions-item>
        <el-descriptions-item label="任务总数">{{ projectInfo.infoCount }}</el-descriptions-item>
        <el-descriptions-item label="当前延期任务">{{ projectInfo.taskDeferred }}</el-descriptions-item>
        <el-descriptions-item label="延期任务天数">{{ projectInfo.taskDeferredDay }}天</el-descriptions-item>
        <el-descriptions-item label="项目总体进度延期天数">{{ projectInfo.projectDeferredDay }}天</el-descriptions-item>
      </el-descriptions>
    </div>
    <div class="project-search">
      <!-- <el-input
        v-model.trim="searchForm.taskTitle"
        placeholder="任务名称"
        style="width: 150px"
        @keydown.enter="getProjectProgressInfoData"></el-input> -->
      <InputSearch
        v-model.trim="searchForm.taskTitle"
        placeholder="任务名称"
        style="width: 170px"
        @handleQuery="getProjectProgressInfoData"></InputSearch>
      <el-select
        v-model="searchForm.currentStatus"
        placeholder="任务状态"
        clearable
        style="width: 170px"
        @change="getProjectProgressInfoData">
        <el-option
          v-for="(item, index) in dict.dictMap['task_status']"
          :key="index"
          :label="item.dictLabel"
          :value="item.dictValue"></el-option>
      </el-select>
      <el-select
        v-model="searchForm.taskUserId"
        placeholder="任务责任人"
        clearable
        style="width: 170px"
        @change="getProjectProgressInfoData">
        <el-option
          v-for="(item, index) in projectMemberList"
          :key="index"
          :label="item.userName"
          :value="item.userId"></el-option>
      </el-select>
      <div class="view-type">
        <el-radio-group v-model="tabVal" class="tab-radio-group" @change="tabChangRadio">
          <el-radio-button label="甘特图" :value="1" border />
          <el-radio-button label="日历" :value="2" border />
        </el-radio-group>
      </div>
    </div>
    <div class="project-gantt">
      <!-- 避免甘特图无法渲染 -->
      <GanttChart
        v-show="tabVal === 1"
        :list="tasks"
        :columns="columns"
        default-expand-all
        :options="{ height: '100%', type: 'hour', props: { children: 'childrenList' } }"></GanttChart>

      <TaskCalendar v-if="tabVal === 2" disabled />
    </div>
    <AddTask
      v-model:visible="addTaskVisible"
      :project-id="props.projectId"
      :item-id="taskForm.itemId"
      :parentData="parentData"
      @submitFinish="getProjectProgressInfoData"
      @close="handleAddTaskClose"></AddTask>
  </div>
</template>

<style scoped lang="scss">
.project-progress {
  height: 100%;
  width: 100%;
  .project-info {
    width: 80%;
    :deep(.elp-descriptions__label) {
      color: var(--elp-text-color-regular);
    }
    :deep(.elp-descriptions__content) {
      color: var(--elp-text-color-primary);
    }
  }
  .project-search {
    @include use-flex(center);
    margin-bottom: 10px;
    .elp-input,
    .elp-select {
      margin-right: 10px;
    }
  }
  .project-gantt {
    height: calc(100% - 161px);
    :deep(.elp-form-item) {
      margin-bottom: 0;
    }
  }
  :deep(.elp-date-editor) {
    --elp-date-editor-width: 100%;
  }
  :deep(.elp-input-number) {
    width: 100%;
  }
  :deep(.elp-icon) {
    cursor: pointer;
    & + .elp-icon {
      margin-left: 5px;
    }
  }
}
</style>
